#ifndef __YUECHUAN_MUTEX_H__
#define __YUECHUAN_MUTEX_H__

#include <thread>
#include <pthread.h>
#include <semaphore.h>
#include <stdexcept>
#include <atomic>
#include "noncopyable.h"


namespace yuechuan {
    /**
     * @brief 继承与Noncopyable为了实现不可被复制，引用，赋值
     * @details 这样就不许要在写代码使得赋值，引用，复制的函数为删除的了
     */
    class Semaphore : Noncopyable {
    public:
        /**
         * @brief 初始化信号量，构造函数
         * @param count 信号量初值
         */
        Semaphore(uint32_t count = 0);
        /**
         * @brief 信号量的析构函数
         */
        ~Semaphore();

        /**
        * @brief 使信号量数量减一，当信号量为0时，阻塞
        */
        void wait();

        /**
         * @brief 使信号量数量加一，当信号量数目大于定义的数目时，阻塞
         */
        void notify();

    private:
        sem_t m_semaphore; /// 信号量的值
    };

    /**
     * @brief 局部锁的模板实现
     */
    template<class T>
    struct ScopedLockImpl {
    public:
        /**
         * @brief 通过类的创建来进行加锁，类对象的析构来进行解锁
         * @param mutex 互斥量的引用，无论传递什么类型的互斥量这里构造方法都执行其对应的加锁方法
         */
        ScopedLockImpl(T &mutex) : m_mutex(mutex) {
            m_mutex.lock();
            m_locked = true;
        }

        ~ScopedLockImpl() {
            unlock();
        }

        void lock() {
            if (!m_locked) {
                m_mutex.lock();
                m_locked = true;
            }
        }

        void unlock() {
            if (m_locked) {
                m_mutex.unlock();
                m_locked = false;
            }
        }

    private:
        T &m_mutex;
        bool m_locked;
    };

    /**
     * @brief 局部读锁模板实现
     */
    template<class T>
    struct ReadScopedLockImpl {
    public:
        ReadScopedLockImpl(T &mutex) : m_mutex(mutex) {
            m_mutex.rdlock();
            m_locked = true;
        }

        ~ReadScopedLockImpl() {
            unlock();
        }

        void lock() {
            if (!m_locked) {
                m_mutex.rdlock();
                m_locked = true;
            }
        }

        void unlock() {
            if (m_locked) {
                m_mutex.unlock();
                m_locked = false;
            }
        }

    private:
        T &m_mutex;
        bool m_locked;
    };

    /**
     * @brief 局部写锁模板实现
     */
    template<class T>
    struct WriteScopedLockImpl {
    public:
        WriteScopedLockImpl(T &mutex)
                : m_mutex(mutex) {
            m_mutex.wrlock();
            m_locked = true;
        }


        ~WriteScopedLockImpl() {
            unlock();
        }


        void lock() {
            if (!m_locked) {
                m_mutex.wrlock();
                m_locked = true;
            }
        }

        void unlock() {
            if (m_locked) {
                m_mutex.unlock();
                m_locked = false;
            }
        }

    private:
        T &m_mutex;
        bool m_locked;
    };
    /**
     * @brief 局部一般锁的实现
     */
    class Mutex : Noncopyable {
    public:
        typedef ScopedLockImpl<Mutex> Lock;

        Mutex() {
            pthread_mutex_init(&m_mutex, nullptr);
        }

        ~Mutex() {
            pthread_mutex_destroy(&m_mutex);
        }

        void lock() {
            pthread_mutex_lock(&m_mutex);
        }

        void unlock() {
            pthread_mutex_unlock(&m_mutex);
        }

    private:
        pthread_mutex_t m_mutex;
    };

    /**
     * @brief 没有作用的一般锁，方便在调试时显示加锁和不加锁的区别
     */
    class NullMutex : Noncopyable {
    public:
        typedef ScopedLockImpl<NullMutex> Lock;

        NullMutex() {}

        ~NullMutex() {}

        void lock() {}

        void unlock() {}

    };
    /**
     * @brief 没有作用的读写锁，方便在调试时显示加锁和不加锁的区别
     */
     class NullRWMutex: Noncopyable{
     public:
         typedef ReadScopedLockImpl<NullRWMutex> ReadLock;
         typedef WriteScopedLockImpl<NullRWMutex> WriteLock;

         NullRWMutex() {}

         ~NullRWMutex() {}

         void lock() {}

         void unlock() {}
     };
    /**
     * @brief 读写锁
     */
    class RWMutex : Noncopyable {
    public:
        /**
         * @brief 实现读写锁的分离
         * @details 对于网络服务器而言，读多写少，实现读写锁分离可提升效率
         */
        typedef ReadScopedLockImpl<RWMutex> ReadLock;
        typedef WriteScopedLockImpl<RWMutex> WriteLock;
        /**
         * @brief 读写锁互斥量的初始化
         */
        RWMutex() {
            pthread_rwlock_init(&m_lock, nullptr);
        }

        ~RWMutex() {
            pthread_rwlock_destroy(&m_lock);
        }

        void rdlock() {
            pthread_rwlock_rdlock(&m_lock);
        }

        void wrlock() {
            pthread_rwlock_wrlock(&m_lock);
        }

        void unlock() {
            pthread_rwlock_unlock(&m_lock);
        }

    private:
        pthread_rwlock_t m_lock;
    };

    /**
     * @brief 自旋锁
     * @details 自旋锁是“原地等待”的方式解决资源冲突的，一个线程获得自旋锁后，另一个线程期望获得该自旋锁，获取不到，只能原地“打转”处于
     *          忙等待状态，这样会占用一定的CPU资源，但是冲突时间比较短，所以不应该被线程长时间持有
     *          在中断上下文的环境下，首选spinLock
     *          首先会在CPU进行忙等，当等待一定次数后就会进入内核等待
     */
    class SpinLock : Noncopyable {
    public:
        typedef ScopedLockImpl<SpinLock> Lock;

        SpinLock() {
            pthread_spin_init(&m_mutex, 0);
        }

        ~SpinLock() {
            pthread_spin_destroy(&m_mutex);
        }

        void lock() {
            pthread_spin_lock(&m_mutex);
        }

        void unlock() {
            pthread_spin_unlock(&m_mutex);
        }

    private:
        pthread_spinlock_t m_mutex;
    };

    /**
     * @brief 原子锁
     * @details 使用原子操作来实现线程间同步，当锁已经被占用，则会自旋等待直到锁被释放
     *          原子锁更适用于广泛情况，可以保持线程同步，但是会导致线程阻塞
     *          自旋锁就是通过原子锁实现的
     *          我们实现的原子锁在尝试加锁的时候是在一个循环中，相对于自旋锁而言，不会进入内核等待，一直处于忙等，效率会比自旋锁低
     */
    class CASLock : public Noncopyable{
    public:
        typedef ScopedLockImpl<CASLock> Lock;
        CASLock(){
            m_mutex.clear();
        }
        ~CASLock(){

        }

        void lock(){
            while(std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
        }

        void unlock(){
            std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
        }

    private:
        volatile std::atomic_flag m_mutex;
    };
} // namespace yuechuan


#endif